package com.kimi.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.kimi.commons.ErrorCode;
import com.kimi.exception.BusinessException;
import com.kimi.mapper.UserMapper;
import com.kimi.pojo.domain.User;
import com.kimi.pojo.request.UserLoginRequest;
import com.kimi.pojo.request.UserRegisterRequest;
import com.kimi.service.UserService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

import static com.kimi.constants.UserConstant.*;

/**
 * @author Kimi
 * @description 针对表【tb_user(用户表)】的数据库操作Service实现
 * @createDate 2025-03-16 20:47:14
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService {
    @Resource
    private UserMapper userMapper;
    /**
     * 用户注册
     * @param userRegisterRequest
     * @return
     */
    @Override
    public User userRegister(UserRegisterRequest userRegisterRequest) {
        String account = userRegisterRequest.getAccount();
        String password = userRegisterRequest.getPassword();
        String checkPassword = userRegisterRequest.getCheckPassword();
        checkAccount(account);
        checkPassword(password);
        checkPassword(checkPassword);
        if (!password.equals(checkPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "两次密码不一致");
        }
        if (query().eq("account", account).count() > 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号重复");
        }
        String encryptPassword = encryptPassword(password);
        User user = new User();
        user.setAccount(account);
        user.setUsername(account);
        user.setPassword(encryptPassword);
        boolean save = this.save(user);
        if (!save) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "注册失败");
        }
        return getSafetyUser(user);
    }
    /**
     * 用户登录
     * @param userLoginRequest
     * @param request
     * @return
     */
    @Override
    public User userLogin(UserLoginRequest userLoginRequest, HttpServletRequest request) {
        if (request == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
        }
        String account = userLoginRequest.getAccount();
        String password = userLoginRequest.getPassword();
        checkAccount(account);
        checkPassword(password);
        String encryptPassword = encryptPassword(password);
        User user = this.getOne(new QueryWrapper<User>().eq("account", account).eq("password", encryptPassword));
        if (user == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号或密码错误");
        }
        User userSafety = getSafetyUser(user);
        request.getSession().setAttribute(USER_LOGIN_STATUS, userSafety);
        return userSafety;
    }
    /**
     * 获取脱敏用户信息
     * @param originUser
     * @return
     */
    @Override
    public User getSafetyUser(User originUser) {
        if (originUser != null) {
            User safetyUser = new User();
            safetyUser.setId(originUser.getId());
            safetyUser.setUsername(originUser.getUsername());
            safetyUser.setAccount(originUser.getAccount());
            safetyUser.setAvatarUrl(originUser.getAvatarUrl());
            safetyUser.setGender(originUser.getGender());
            safetyUser.setPhone(originUser.getPhone());
            safetyUser.setEmail(originUser.getEmail());
            safetyUser.setTags(originUser.getTags());
            safetyUser.setBiography(originUser.getBiography());
            safetyUser.setStatus(originUser.getStatus());
            safetyUser.setRole(originUser.getRole());
            return safetyUser;
        }
        return new User();
    }
    /**
     * 用户注销
     * @param request
     * @return
     */
    @Override
    public Boolean userLogout(HttpServletRequest request) {
        if (request == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
        }
        request.getSession().removeAttribute(USER_LOGIN_STATUS);
        return true;
    }

    /**
     * 获取当前登录用户
     * @param request
     * @return
     */
    @Override
    public User getCurrentUser(HttpServletRequest request) {
        if (request == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
        }
        User currentUser = (User) request.getSession().getAttribute(USER_LOGIN_STATUS);
        if (currentUser == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN);
        }
        Long currentUserId = currentUser.getId();
        User user = this.getById(currentUserId);
        return getSafetyUser(user);
    }

    /**
     * 判断是否为管理员
     * @param request
     * @return
     */
    @Override
    public boolean isAdmin(HttpServletRequest request) {
        if (request == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
        }
        User currentUser = (User) request.getSession().getAttribute(USER_LOGIN_STATUS);
        return currentUser != null && Objects.equals(currentUser.getRole(), ADMIN_ROLE);
    }
    /**
     * 根据用户名搜索用户（模糊查询）
     *
     * @param username 用户名
     * @return
     */
    @Override
    public List<User> searchUser(String username) {
        if (StrUtil.isBlank(username)) {
            List<User> list = this.list();
            return list.stream().map(this::getSafetyUser).collect(Collectors.toList());
        }
        List<User> list = this.list(new QueryWrapper<User>().like("username", username));
        return list.stream().map(this::getSafetyUser).collect(Collectors.toList());
    }
    /**
     * 根据标签搜索用户（内存过滤）
     *
     * @param tagNameList 用户要拥有的标签
     * @return
     */
    @Override
    public List<User> searchUsersByTags(List<String> tagNameList) {
        if (CollectionUtils.isEmpty(tagNameList)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 1. 先查询所有用户
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        List<User> userList = userMapper.selectList(queryWrapper);
        Gson gson = new Gson();
        // 2. 在内存中判断是否包含要求的标签
        return userList.stream().filter(user -> {
            String tagsStr = user.getTags();
            if (StrUtil.isBlank(tagsStr)) {
                return false;
            }
            Set<String> tempTagNameSet = gson.fromJson(tagsStr, new TypeToken<Set<String>>() {
            }.getType());
            tempTagNameSet = Optional.ofNullable(tempTagNameSet).orElse(new HashSet<>());
            for (String tagName : tagNameList) {
                if (!tempTagNameSet.contains(tagName)) {
                    return false;
                }
            }
            return true;
        }).map(this::getSafetyUser).collect(Collectors.toList());
    }
    /**
     * 更新用户信息
     * @param user
     * @param request
     * @return
     */
    @Override
    public Integer updateUser(User user,HttpServletRequest request) {
        long userId = user.getId();
        User loginUser = getCurrentUser(request);
        if (userId <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // todo 补充校验，如果用户没有传任何要更新的值，就直接报错，不用执行 update 语句
        // 如果是管理员，允许更新任意用户
        // 如果不是管理员，只允许更新当前（自己的）信息
        if (!isAdmin(request) && userId != loginUser.getId()) {
            throw new BusinessException(ErrorCode.NO_AUTH);
        }
        User oldUser = userMapper.selectById(userId);
        if (oldUser == null) {
            throw new BusinessException(ErrorCode.NULL_ERROR);
        }
        return userMapper.updateById(user);
    }

    /**
     * 对密码进行md5加密
     *
     * @param password
     * @return
     */
    private String encryptPassword(String password) {
        //使用MD5加密
        return SecureUtil.md5(password);
    }
    /**
     * 校验密码格式
     *
     * @param password
     */
    private void checkPassword(String password) {
        if (StrUtil.isBlank(password)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码不能为空");
        }
        if (password.length() < MINIMUM_PASSWORD_LENGTH) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码过短");
        }
    }

    /**
     * 校验账号格式
     * @param account
     */
    private void checkAccount(String account) {
        if (StrUtil.isBlank(account)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号不能为空");
        }
        if (account.length() < MINIMUM_ACCOUNT_LENGTH) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号过短");
        }
        //正则表达式校验，匹配字母、数字、下划线、减号，数字不能开头
        if (!account.matches("^[a-zA-Z][a-zA-Z0-9_-]*$")) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号格式错误");
        }

    }
}




